package org.oimwrapper.connectors.common;


import java.util.*;
import java.util.regex.*;import org.oimwrapper.connectors.*;

/**
 * Reconcilies child table entries in separate resource objects.<p>
 *
 * This task expects the following parameters, in addition to the standard
 * parameters in the {@link OIMReconTaskBase} class.
 * <ul>
 * <li><code>SourceObject</code> The name of the resource object to use as a source for this reconciliation.</li>
 * <li><code>FilterLookup</code> The name of a lookup table that contains a list of attribute values in the encode, 
 *                           and the child form column in which those attributes are found in the decode.</li>
 * </ul>
 */
public class OIMChildDataRecon extends OIMReconTaskBase {

	/**
	 * The name of the source resource object to reconcile from.
	 */
	protected String source;

	/**
	 * Stores the map of entries to filter on, if requested.
	 */
	protected Map filter;

	/**
	 * True is a filter is to be used, false if all records should be reconcilied.
	 */
	protected boolean doFilter;

	/**
	 * Default constructor.
	 */
	public OIMChildDataRecon() {
		super("OIMWRAPPER.TASK");
	}

	/**
	 * This method is called once per task, and should initialize and open a connection to the target system.
	 * 
	 * @exception Exception
	 */
	public void openConnection() throws Exception {
		source = getCriticalAttribute("SourceObject");
		doFilter = isEmpty(getCriticalAttribute("FilterLookup"));
		filter = getLookupValues(getCriticalAttribute("FilterLookup"));
	}

	/**
	 * This method is called once per task, and should close the open connection to the target system.
	 *
	 * @exception Exception
	 */
	public void closeConnection() throws Exception { ; }

	/**
	 * This method is called once to retrieve a List of records on the target system.   The objects in this 
	 * list are consumed by the <code>getSingleValuedData()</code> and <code>getMultiValuedData()</code>
	 * methods, and not directly used by any other methods.
	 * 
	 * @return A List of records on the target system.
	 * @exception Exception
	 */
	public List getRecords() throws Exception {
		List result = new ArrayList();
		long[] processInstanceKeys = getResourceInstances(source);
		for (int i = 0; i < processInstanceKeys.length; i++) {
			Map parentFormData = getProcessFormValues(processInstanceKeys[i]);
			boolean submitRecord = !doFilter;
			String[] childTables = getChildTables(processInstanceKeys[i]);
			for (int j = 0; !submitRecord && j < childTables.length; j++) {
				Map[] childData = getProcessFormChildValues(processInstanceKeys[i], childTables[j]);
				for (int k = 0; !submitRecord && k < childData.length; k++) {
					for (Iterator iterator = filter.keySet().iterator(); !submitRecord && iterator.hasNext(); ) {
						String filterValue = (String) iterator.next();
						String filterColumn = (String) filter.get(filterValue);
						if (childData[k].containsKey(filterColumn)) {
							String childDataValue = (String) childData[k].get(filterColumn);
							submitRecord = Pattern.compile(filterValue).matcher(childDataValue).matches();
						}
					}
				}
			}
			if (submitRecord) {
				result.add(parentFormData);
			}
		}
		return result;
	}

	/**
	 * This method is called to convert the single-valued data in the arbitrary Record Object to a Map
	 * containing attribute names as the key, and the corresponding attribute value as the value.
	 * 
	 * @param Record An arbitrary object that contains the data for a single event.
	 * @return A Map containing the attribute value pairs from the record for all single-valued attributes.
	 * @exception Exception
	 */
	public Map getSingleValuedData(Object Record) throws Exception {
		return (Map) Record;
	}

	/**
	 * This method is called to convert the multi-valued data in the arbitrary Record Object to a Map
	 * containing attribute names as the key, and an Array of Maps for the value.  The Maps in the 
	 * value should contain attribute value pairs for each child record, and one Map should be present
	 * in the array for each child element.
	 * 
	 * @param Record An arbitrary object that contains the data for a single event.
	 * @return A Map containing the attribute value pairs from the record for all multi-valued attributes.
	 * @exception Exception
	 */
	public Map getMultiValuedData(Object Record) throws Exception {
		return new HashMap();
	}
}